<template>
    <div class="carousel-container" :style="{ width: width, height: height }">
        <div class="carousel-list" ref="listRef">
            <div
                class="list-item"
                v-for="(item, index) in listDataComputed"
                :key="item"
                @click="handleClickListItem(item, index - 1)"
                v-randomBgColor>
                <img :src="item" alt="" />
            </div>
        </div>
        <div class="carousel-arrow carousel-arrow-left" @click="handleClickArrowLeft">
            <LeftOutlined />
        </div>
        <div class="carousel-arrow carousel-arrow-right" @click="handleClickArrowRight">
            <RightOutlined />
        </div>
        <div class="carousel-indicators" v-if="indicator">
            <div
                :class="['indicator-item', curentActiveIndex === index ? 'active' : '']"
                v-for="(_item, index) in imagesList"
                :key="index"
                @click="handleClickIndicator(index)"></div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { LeftOutlined, RightOutlined } from "@ant-design/icons-vue";
import { onMounted } from "vue";
import { computed, ref } from "vue";
import { Emits, Props } from "./carousel";

const { imagesList, duration, autoPlay, autoPlayInterval, width, height, indicator } = withDefaults(
    defineProps<Props>(),
    {
        imagesList: () => ["1", "2", "3"],
        duration: 500,
        autoPlay: true,
        autoPlayInterval: 3000,
        width: "100%",
        height: "300px",
        indicator: true
    }
);
const emits = defineEmits<Emits>();

const listDataComputed = computed(() => [imagesList[imagesList.length - 1], ...imagesList, imagesList[0]]);

// 轮播元素dom
const listRef = ref<HTMLDivElement | null>(null);
// 当前轮播的图片索引，该索引相对的是原轮播数据 imagesList
const curentActiveIndex = ref(0);

// 轮播
const moveTo = (index: number) => {
    listRef.value!.style.transition = `transform ${duration / 1000}s ease`;
    // 最前面多加了一个元素，因此平移距离要（索引 +1）* 100%
    listRef.value!.style.transform = `translateX(-${(index + 1) * 100}%)`;
    setTimeout(() => {
        listRef.value!.style.transition = "none";
    }, duration);
    curentActiveIndex.value = index;
    emits("change", imagesList[index], index);
};

// 指示器点击事件
const handleClickIndicator = (index: number) => moveTo(index);

// 箭头点击事件
const handleClickArrowRight = () => {
    if (curentActiveIndex.value >= imagesList.length - 1) {
        // 向后无缝轮播

        // 闪现到首位元素
        listRef.value!.style.transition = "none";
        listRef.value!.style.transform = `translateX(0)`;

        // 强制重绘
        getComputedStyle(listRef.value!).getPropertyValue("transform");
        moveTo(0);

        // 优化重绘
        // requestAnimationFrame(() => moveTo(0));
    } else {
        // 向后普通轮播
        const targetIndex = curentActiveIndex.value + 1;
        moveTo(targetIndex);
    }
};
const handleClickArrowLeft = () => {
    if (curentActiveIndex.value <= 0) {
        // 向前无缝轮播
        listRef.value!.style.transition = "none";
        listRef.value!.style.transform = `translateX(-${(imagesList.length + 1) * 100}%)`;
        getComputedStyle(listRef.value!).getPropertyValue("transform");
        moveTo(imagesList.length - 1);
        // requestAnimationFrame(() => moveTo(imagesList.length - 1));
    } else {
        const targetIndex = curentActiveIndex.value - 1;
        moveTo(targetIndex);
    }
};

// 点击当前轮播卡片
const handleClickListItem = (item: (typeof imagesList)[0], index: number) => {
    emits("content-item-click", item, index);
};

// 自动轮播
const handleAutoPlay = () => {
    if (!autoPlay) return;
    setInterval(handleClickArrowRight, autoPlayInterval);
};

onMounted(() => handleAutoPlay());
</script>

<style scoped lang="scss">
.carousel-container {
    position: relative;
    margin: 0 auto;
    overflow: hidden;
    .carousel-list {
        display: flex;
        align-items: center;
        width: 100%;
        height: 100%;
        transform: translateX(-100%);
        .list-item {
            flex: 0 0 100%;
            width: 100%;
            height: 100%;

            /* height: 300px; */
            img {
                width: 100%;
                height: 100%;
                object-fit: cover;
                object-position: center;
                cursor: pointer;
                user-select: none;
            }
        }
    }
    .carousel-arrow {
        position: absolute;
        top: 50%;
        z-index: 10;
        display: flex;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        font-size: 16px;
        color: #ffffff;
        cursor: pointer;
        background-color: rgb(0 0 0 / 30%);
        border-radius: 50%;
        opacity: 0;
        transition: all 0.3s ease;
        transform: translateY(-50%);
        &:hover {
            background-color: rgb(0 0 0 / 40%);
        }
    }
    .carousel-arrow-left {
        left: 0;
    }
    .carousel-arrow-right {
        right: 0;
    }
    &:hover {
        .carousel-arrow-left {
            left: 20px;
            opacity: 1;
        }
        .carousel-arrow-right {
            right: 20px;
            opacity: 1;
        }
    }
    .carousel-indicators {
        position: absolute;
        bottom: 10px;
        left: 50%;
        display: flex;
        justify-content: center;
        margin-top: 10px;
        cursor: pointer;
        transition: all 0.3s ease;
        transform: translateX(-50%);
        .indicator-item {
            width: 10px;
            height: 10px;
            margin: 0 6px;
            background-color: #666666;
            border-radius: 50%;
            &:hover {
                border: 1px solid #ffffff;
            }
        }
        .active {
            background-color: #ffffff;
        }
    }
}
</style>
